#include "GameObjectManager.h"

#include "Game.h"
#include "Movable.h"
#include "Tile.h"

#include <iostream>


GameObjectManager* GameObjectManager::gameObjectManager = 0;


GameObjectManager* GameObjectManager::getInstance()
{
	if (!gameObjectManager)
	{
		gameObjectManager = new GameObjectManager();
	}

	return gameObjectManager;
}


void GameObjectManager::destroyInstance()
{
	delete gameObjectManager;
	gameObjectManager = 0;
}


void GameObjectManager::update()
{
	// Add new movables
	for (Movables::iterator it = movablesToAdd.begin(); it != movablesToAdd.end(); ++it)
	{
		movables.push_back(*it);
	}
	movablesToAdd.clear();

	bool hasPlayers = false;
	// Performs a move for all movables (players, bots, projectiles).
	for (Movables::iterator it = movables.begin(); it != movables.end(); ++it)
	{
		if ((*it)->isDestroyed())
			continue;

		if ((*it)->getType() == GameObject::Type_Player)
		{
			hasPlayers = true;
		}

		// Current location of the player and the desired direction.
		int x, y;
		int hDirection = 0;
		int vDirection = 0;
		(*it)->getLocation(x, y);

		// Attempt moving.
		(*it)->getDesiredMove(hDirection, vDirection);

		// Move is not attempted, skip.
		if (hDirection == 0 && vDirection == 0)
			continue;

		int xDesired = x + hDirection;
		int yDesired = y + vDirection;

		// Map bounds check;
		if (!map->isWithinBounds(xDesired, yDesired))
		{
			(*it)->handleCollision(0);
			continue;
		}

		// Execute move if a move to the desired spot is possible.
		if ((*map)[yDesired][xDesired]->isPassable((*it))) 
		{
			// Move is possible.
			(*it)->setVelocity(hDirection, vDirection);
			(*map)[y][x]->remove(*it);
			(*map)[yDesired][xDesired]->add(*it);
			break;
		}
		else
		{
			// Let the movable handle the collisions.
			std::vector<GameObject*> unPassableObjects;
			(*map)[yDesired][xDesired]->getUnPassableObjects(unPassableObjects, *it);
			for (std::vector<GameObject*>::iterator it2 = unPassableObjects.begin(); it2 != unPassableObjects.end(); ++it2)
			{
				(*it)->handleCollision(*it2);
			}
		}
	}

	// Clean up movables.
	for (Movables::iterator it = movables.begin(); it != movables.end();)
	{
		if ((*it)->isDestroyed())
		{
			it = movables.erase(it);
		}
		else
		{
			++it;
		}
	}

	// Clean up map and memory.
	for (GameObjects::iterator it = gameObjectsToDelete.begin(); it != gameObjectsToDelete.end(); ++it)
	{
		int x, y;
		(*it)->getLocation(x, y);
		(*map)[y][x]->remove(*it);
		delete *it;			
	}
	gameObjectsToDelete.clear();

	// Check for game over
	if (!hasPlayers)
		Game::getInstance()->dungeonOver("All players have died!", false);
}


void GameObjectManager::registerMovable(Movable* movable)
{
	movablesToAdd.push_back(movable);
}


void GameObjectManager::registerObjectForDeletion(GameObject* gameObject)
{
	gameObjectsToDelete.push_back(gameObject);
}


void GameObjectManager::setMap(Map* map)
{
	this->map = map;
}


GameObjectManager::GameObjectManager()
{
}


